﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace McHotspoot
{
    public class MatLab : McHotspotI
    {
        public string execute(string key, double n, double index, string codein, out string message)
        {
            string filename = "process";
            string filesRoot = RoleEnvironment.GetLocalResource("McCloudStorage").RootPath;
            string matlab1 = Path.Combine(filesRoot, filename + ".exe");
            string output1 = "P_" + key + index + ".csv";
            exec(matlab1, new string[] {n.ToString(), index.ToString(), codein, output1}, out message);
            FileStream fileStream = new FileStream(output1, FileMode.Open);
            StreamReader reader = new StreamReader(fileStream);
            string r = reader.ReadToEnd();
            fileStream.Close();
            return r;            
        }

        public string finish(string key, double n, string r, string codein, string codeout, out string message)
        {
            string filename = "merge";
            string filesRoot = RoleEnvironment.GetLocalResource("McCloudStorage").RootPath;
            string matlab2 = Path.Combine(filesRoot, filename + ".exe");
            string output1 = r;            
            string output2 = "M_" + key + ".csv";
            exec(matlab2, new string[] { n.ToString(), codeout, output1, output2 }, out message);
            string m = "";
            FileStream fileStream2 = new FileStream(output2, FileMode.OpenOrCreate);
            StreamReader reader = new StreamReader(fileStream2);
            m = reader.ReadToEnd();
            fileStream2.Close();
            return m;            
        }

        public void optimization(double n, string codein, string codeout, double npt, 
            out double ninstancesadded, out double ntasks, out int timeoutInSeconds)
        {
            if (npt != 0)
            {
                ntasks = (double)Math.Truncate((decimal)(n / npt));
                if (n > (ntasks * npt)) ntasks++;
            }
            else { ntasks = 19; }            
            ninstancesadded = 0;
            timeoutInSeconds = 2 * 60 * 60;
        }

        public string test(string key, double n, string codein, string codeout, double npt)
        {
            bool ok = true;
            if (n < 0) ok = false;
            if (Math.Truncate(n) < n) ok = false;
            if (npt < 0) ok = false;
            if (Math.Truncate(npt) < npt) ok = false;
            if (npt > n) ok = false;            
            if(ok) return "";
            else return "Error: Input error!";

            string message = "";
            double x = 2;
            string r = execute(key, x, 1, codein, out message);
            string filesRoot = RoleEnvironment.GetLocalResource("McCloudStorage").RootPath;
            string file = Path.Combine(filesRoot, key + ".temp");
            FileStream fileStream = new FileStream(file, FileMode.Create);
            byte[] bytes = Encoding.Default.GetBytes(r);
            fileStream.Write(bytes, 0, bytes.Length);
            fileStream.Close();
            string m = finish(key, x, file, codein, codeout, out message);
            if (m != "") return "";
            else return "Error: Null Result";
        }
        
        private void exec(string file, string[] arguments, out string message)
        {
            if (!System.IO.File.Exists(file))
            {
                message = "Code not found in: " + file;
                return;
            }
            System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
            psi.FileName = file;
            psi.Arguments = "";
            for (int i = 0; i < arguments.Length; i++)
            {
                psi.Arguments += " \"" + arguments[i] + "\"";
            }
            psi.Arguments = string.Format(psi.Arguments);
            psi.CreateNoWindow = true;
            psi.ErrorDialog = false;
            psi.UseShellExecute = false;
            psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = false;
            psi.RedirectStandardError = true;
                        
            System.Diagnostics.Process exeProcess = System.Diagnostics.Process.Start(psi);
            exeProcess.PriorityClass = System.Diagnostics.ProcessPriorityClass.High;
            exeProcess.OutputDataReceived += 
                new System.Diagnostics.DataReceivedEventHandler(processOutputHandler);
            exeProcess.BeginOutputReadLine();
            string errString = exeProcess.StandardError.ReadToEnd();
            exeProcess.WaitForExit();
            exeProcess.Close();
            message = "Exec: " + psi.FileName + " " + psi.Arguments + "\r\n";
            if (errString != "") message += "Exec Error: " + errString;
            if (_output != "") message += "Exec Output: " + _output;
        }

        private string _output = "";
        private void processOutputHandler(object sendingProcess, 
            System.Diagnostics.DataReceivedEventArgs outLine)
        {
            if (!String.IsNullOrEmpty(outLine.Data)) _output += outLine.Data+"\r\n";
        }
    }
}